package ggmines

import (
	"github.com/shopspring/decimal"
	"sync"
	"wzgames/internal/model/gkindp"
	"wzgames/internal/secure/rng"
	"wzgames/pkg/utils/calcutil"
)

type MineGift struct {
	totalCells int32
	fields     [][]int32
	cellPos    map[int32][]int32

	mu sync.RWMutex
}

func (gf *MineGift) Init(cfg *gkindp.MinesConfig) {
	gf.totalCells = 25
	gf.cellPos = make(map[int32][]int32)

	gf.fields = [][]int32{{1, 2, 3, 4, 5}, {6, 7, 8, 9, 10}, {11, 12, 13, 14, 15}, {16, 17, 18, 19, 20}, {21, 22, 23, 24, 25}}
	l := len(gf.fields)
	gf.mu.Lock()
	for i := 0; i < l; i++ {
		lf := len(gf.fields[i])
		for j := 0; j < lf; j++ {
			cellId := gf.fields[i][j]
			gf.cellPos[cellId] = []int32{int32(i + 1), int32(j + 1)}
		}
	}
	gf.mu.Unlock()
}

func (gf *MineGift) Update(cfg *gkindp.MinesConfig) {

}

func (gf *MineGift) TotalCells() int32 {
	return gf.totalCells
}

func (gf *MineGift) getPosByCellId(cellId int32) []int32 {
	gf.mu.RLock()
	defer gf.mu.RUnlock()
	if v, ok := gf.cellPos[cellId]; ok {
		return v
	}

	return []int32{0, 0}
}

func (gf *MineGift) Calculate(servSeed, clientSeed string, mineAmount int32) []*gkindp.MinePos {
	var holes []int32
	for i := int32(0); i < gf.totalCells; i++ {
		holes = append(holes, i+1)
	}
	limit := int(mineAmount)

	var nums []float64
	if limit > 16 {
		tmp := rng.CalculateHash(servSeed, clientSeed, rng.ChunkSize, 16)
		nums = append(nums, tmp...)
		tmp = rng.CalculateHashWithRound(servSeed, clientSeed, rng.ChunkSize, limit-16, 1)
		nums = append(nums, tmp...)
	} else {
		tmp := rng.CalculateHash(servSeed, clientSeed, rng.ChunkSize, limit)
		nums = append(nums, tmp...)
	}

	var ret []*gkindp.MinePos
	for i := int32(0); i < mineAmount; i++ {
		l := len(holes)
		idx := decimal.NewFromFloat(nums[i]).Mul(decimal.NewFromInt32(int32(l)))
		index := int(idx.IntPart())
		cellPos := gf.getPosByCellId(holes[index])
		ret = append(ret, &gkindp.MinePos{
			Row:  cellPos[0],
			Col:  cellPos[1],
			Cell: holes[index],
		})
		holes = append(holes[:index], holes[index+1:]...)
	}

	return ret
}

func (gf *MineGift) CalcMultiplier(gameConfig *gkindp.MinesConfig, digs int32, mineAmt int32) decimal.Decimal {
	if digs > gf.totalCells-mineAmt {
		digs = gf.totalCells - mineAmt
	}
	u := decimal.NewFromFloat(100.0 - gameConfig.HouseEdge).Div(calcutil.BaseCoefficient)
	mines := decimal.NewFromInt32(mineAmt)
	for v := int32(0); v < digs; v++ {
		x := decimal.NewFromInt32(gf.totalCells - v)
		u = u.Mul(x).Div(x.Sub(mines))
	}
	return u
}

func (gf *MineGift) GetCellByPos(row, col int32) int32 {
	return gf.fields[row-1][col-1]
}

func (gf *MineGift) GetPosByCellId(cellId int32) []int32 {
	gf.mu.RLock()
	defer gf.mu.RUnlock()
	if v, ok := gf.cellPos[cellId]; ok {
		return v
	}

	return []int32{0, 0}
}
